package example.demo.unsafe;

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.CountDownLatch;

/**
 * 、实现AtomicInteger
 */
public class UseUnsafeImplAtomicInteger {

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe;
    private static final long valueOffset;

    static {
        try {
            Class<Unsafe> unsafeClass = Unsafe.class;
            Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            //类变量,所以不需要对象实例
            unsafe = (Unsafe) theUnsafe.get(null);
            valueOffset = unsafe.objectFieldOffset
                    (UseUnsafeImplAtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) {
            throw new Error(ex);
        }
    }

    private volatile int value;

    public void add() {
        int i = value;
        int tryCount = 1;
        //unsafe.compareAndSwapInt(this, valueOffset, value, value + 1) 这里的value的两次读取，
        // 在高并发下，这两个value的值是不一样的
        while (!unsafe.compareAndSwapInt(this, valueOffset, i, i + 1)) {
            //失败了，重新读取
            i = value;
            if (((tryCount++) & 31) == 0) {
                Thread.yield();
                tryCount = 1;
            }
        }
    }

    static int count = 500;
    static CountDownLatch latch = new CountDownLatch(count);
    static CountDownLatch main = new CountDownLatch(count);

    public static void main(String[] args) throws InterruptedException {
        UseUnsafeImplAtomicInteger useUnsafeImplAtomicInteger = new UseUnsafeImplAtomicInteger();
        for (int i = 0; i < count; i++) {
            new Thread(() -> {
                try {
                    latch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                for (int j = 0; j < 100000; j++) {
                    useUnsafeImplAtomicInteger.add();
                }
                main.countDown();
            }).start();
            latch.countDown();
        }
        main.await();
        System.out.println(useUnsafeImplAtomicInteger.value);
    }
}
